<?php
namespace wx;

use wx\WXBizDataCrypt;
use think\facade\Cache;
class Minipro {
    /**
     * @var Object 保存类实例的静态成员变量
     */
    private static $_instance;
    private $config = [];

    /**
     * Single constructor. 私有的构造方法
     */
    private function __construct($config){
        $this->config = array_merge($this->config,$config);
        $this->config['appid'] = $this->config['appid'] ?? env('wechat.appid');
        $this->config['secret'] = $this->config['secret'] ?? env('wechat.secret');
        $this->config['mch_key'] = $this->config['mch_key'] ?? env('wechat.mch_key');
        $this->config['mch_id'] = $this->config['mch_id'] ?? env('wechat.mch_id');
    }

    /**
     * @purpose: 创建__clone方法防止对象被复制克隆
     */
    public function __clone(){
        //E_USER_ERROR只能通过trigger_error($msg, E_USER_ERROR)手动触发。E_USER_ERROR是用户自定义错误类型，可以被set_error_handler错误处理函数捕获，允许程序继续运行。E_ERROR是系统错误，不能被set_error_handler错误处理函数捕获，程序会退出运行
        trigger_error('Clone is not allow!',E_USER_ERROR);
    }

    /**
     * @return Minipro|Object 单例方法,用于访问实例的公共的静态方法
     */
    public static function getInstance($config = []){
        if(!(self::$_instance instanceof self)){
            self::$_instance = new self($config);
        }
        return self::$_instance;
    }

    /**生成带参数小程序二维码
     * @param string $scene     小程序码参数
     * @param string $file_path 图片保存路径
     * @return string
     */
    public function mpQrcode($scene='',$save_path='tmp/tmp.png') {
        $url = 'https://api.weixin.qq.com/wxa/getwxacodeunlimit?access_token=' . $this->getAccessToken()['access_token'];
        create_dir($save_path);
        $post_data = [
            'scene' => $scene
        ];
        $string = curl_post_data($url,json_encode($post_data));
        $res = json_decode($string,true);
        if($res) {
            trigger_error($res['errmsg'],E_USER_ERROR);
        }else {
            //创建并写入数据流，然后保存文件
            file_put_contents($save_path,$string);
            return $save_path;
        }
    }

    /**
     * @param string $content
     * @return bool
     */
    public function msgSecCheck($content='') {
        $url = 'https://api.weixin.qq.com/wxa/msg_sec_check?access_token=' . $this->getAccessToken()['access_token'];
        $json = curl_post_data($url,'{ "content":"'.$content.'" }');
        $res = json_decode($json,true);
        if($res['errcode'] === 0) {
            return true;
        }else {
            return false;
        }
    }

    /**
     * @param $image_path
     * @return bool
     */
    public function imgSecCheck($image_path) {
        $img = @file_get_contents($image_path);
        if(!$img) {
            trigger_error('file_get_contents(): php_network_getaddresses: getaddrinfo failed: Name or service not known',E_USER_ERROR);
        }
        $tmpfile = '/dev/shm/tmp1.png';
        file_put_contents($tmpfile,$img);
        $minetype = 'image/jpeg';
        $curl_file = curl_file_create($tmpfile,$minetype);
        $post['media'] = $curl_file;
        $url = 'https://api.weixin.qq.com/wxa/img_sec_check?access_token=' . $this->getAccessToken()['access_token'];
        $json = curl_post_data($url,$post);
        $res = json_decode($json,true);
        if($res['errcode'] === 0) {
            return true;
        }else {
            return false;
        }
    }

    /**
     * @param string $sessionKey
     * @param string $encryptedData
     * @param string $iv
     * @return mixed
     */
    public function decryptData($sessionKey='',$encryptedData='',$iv='') {
        $pc = new WXBizDataCrypt($this->config['appid'], $sessionKey);
        $errCode = $pc->decryptData($encryptedData, $iv, $data );
        if($errCode !== 0) {
            trigger_error('解析失败' . $errCode,E_USER_ERROR);
        }else {
            return json_decode($data,true);
        }
    }

    /**
     * @param $code
     * @return mixed
     */
    public function code2Session($code) {
        $url = 'https://api.weixin.qq.com/sns/jscode2session?appid='.$this->config['appid'].'&secret='.$this->config['secret'].'&js_code='.$code.'&grant_type=authorization_code';
        $json = curl_get_data($url);
        $res = json_decode($json,true);
        if(!$res || (isset($res['errcode']) && $res['errcode'] !== 0)) {
            mylog(__FUNCTION__,$json,'Minipro.log');
            trigger_error($res['errmsg'],E_USER_ERROR);
        }
        return $res;
    }

    public function getAccessToken() {
        $res = Cache::get("mp:access_token");
        if(!$res) {
            mylog(__FUNCTION__,"get mp:access_token failed",'Minipro.log');
//            trigger_error("get mp:access_token failed",E_USER_ERROR);
            $res = $this->genAccessToken();
        }else if($res->create_time + 3600 < time()) {
            // 时间过半, 获取新token
            $res = $this->genAccessToken();
        }
        return $res;
    }

    public function genAccessToken() {
        $url = 'https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid='.$this->config["appid"].'&secret='.$this->config['secret'];
        $json = curl_get_data($url);
        $res = json_decode($json,true);
        if(isset($res['errcode']) && $res['errcode'] !== 0) {
            mylog(__FUNCTION__,$json,'Minipro.log');
            trigger_error($res['errmsg'],E_USER_ERROR);
        }
        $input = [
            'access_token' => $res['access_token'],
            'expires_in' => $res['expires_in'],
            'errcode' => 0,
            'errmsg' => "",
            'create_time' => time()
        ];
        Cache::set("mp:access_token",$input);
        return $input;
    }

    public function getTemplateList() {
        $url = 'https://api.weixin.qq.com/wxaapi/newtmpl/gettemplate?access_token=' . $this->getAccessToken()['access_token'];
        $json = curl_get_data($url);
        return json_decode($json,true);
    }

    /**
     * @param array $options
     * @return mixed
     */
    public function send($options = []) {
        $url = 'https://api.weixin.qq.com/cgi-bin/message/subscribe/send?access_token=' . $this->getAccessToken()['access_token'];
        $json = curl_post_data($url,json_encode($options));
        return json_decode($json,true);
    }

    public function orderUnify($options) {
        $url = 'https://api.mch.weixin.qq.com/pay/unifiedorder';
        $post_data['appid'] = $this->config['appid'];
        $post_data['mch_id'] = $this->config['mch_id'];
        $post_data['nonce_str'] = randomkeys(32);
        $post_data['sign_type'] = 'MD5';
        $post_data['body'] = $options['body'];
        $post_data['out_trade_no'] = $options['out_trade_no'];
        $post_data['total_fee'] = $options['total_fee'];
        $post_data['spbill_create_ip'] = $_SERVER['SERVER_ADDR'];
        $post_data['notify_url'] = $options['notify_url'];
        $post_data['trade_type'] = $options['trade_type'];
        $post_data['openid'] = $options['openid'];
        $post_data['sign'] = $this->get_sign($post_data);

        $xml = curl_post_data($url,array2xml($post_data));
        $res = xml2array($xml);
        if($res['return_code'] == 'FAIL') {
            trigger_error($res['return_msg'],E_USER_ERROR);
        }
        return $res;
    }

    public function get_sign($param) {
        $param = array_filter($param);
        if(isset($param['sign'])) {
            unset($param['sign']);
        }
        ksort($param);
        $query = http_build_query($param)."&key=" . $this->config['mch_key'];
        $query = urldecode($query);
        return  strtoupper(md5($query));
    }





}